package lzupdater.net;

import java.net.HttpURLConnection;
import java.net.URL;

import lzupdater.locale.LocalizedString;
import lzupdater.log.Logger;
import lzupdater.utils.Text;

//LZRosterUpdater, a java client to update LZRoster
//Copyright (C) 2008 Fraskor from Krasus (e-mail: fraskor@gmail.com)
//
//This file is part of LZRosterUpdater.
//
//LZRosterUpdater is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

/**
 * 
 * @author Fraskor
 */
public class HTTPClient {

	private final static LocalizedString createUrlFrom = new LocalizedString(
			"Create URL from '%s'");
	private final static LocalizedString sendCookies = new LocalizedString(
			"Send cookies:");
	private final static LocalizedString cookiesSent = new LocalizedString(
			"Cookies sent.");
	private final static LocalizedString sendPostData = new LocalizedString(
			"Send POST data:");
	private final static LocalizedString postDataSent = new LocalizedString(
			"POST data sent.");
	private final static LocalizedString getServerResponse = new LocalizedString(
			"Get response from the server");
	private final static LocalizedString responseCode = new LocalizedString(
			"Response code = %d");
	private final static LocalizedString getCookies = new LocalizedString(
			"Get cookies");
	private final static LocalizedString getHeaderInformation = new LocalizedString(
			"Get header information");
	private final static LocalizedString getHTMLPageSource = new LocalizedString(
			"Get HTML page source");
	private final static LocalizedString unknownErrorWhenConnecting = new LocalizedString(
			"Unknown error when connecting to : '%s'");
	private final static LocalizedString errorWhenConnecting = new LocalizedString(
			"Error when connecting to : '%s' (%s)");
	private final static LocalizedString startConnection = new LocalizedString(
			"Start connection to : '%s'");
	private final static LocalizedString redirectConnection = new LocalizedString(
			"Redirect connection to '%s'");

	private static boolean thrower = true;
	private static boolean performRedirection = true;

	private HTTPData data = new HTTPData();

	private HTTPClient(String address, Cookies cookies, PostData postData,
			Logger logger) {
		HttpURLConnection connection = null;
		data.setAddress(address);
		try {
			logger.debug(createUrlFrom.useAsFormater(address));
			connection = (HttpURLConnection) new URL(address).openConnection();
			connection.setInstanceFollowRedirects(false);

			if (cookies != null) {
				logger.debug(sendCookies);
				cookies.dump(logger);
				cookies.sendCookies(connection);
				logger.debug(cookiesSent);
			}

			if (postData != null) {
				logger.debug(sendPostData);
				postData.dump(logger);
				postData.sendPostData(connection);
				logger.debug(postDataSent);
			}

			logger.debug(getServerResponse);
			data.setResponseCode(connection.getResponseCode());
			logger.debug(responseCode.useAsFormater(data.getResponseCode()));
			logger.debug(getCookies);
			data.setCookies(new Cookies(connection, logger));
			data.getCookies().dump(logger);
			logger.debug(getHeaderInformation);
			data.setHeader(new HTTPHeader(connection));
			data.getHeader().dump(logger);
			logger.debug(getHTMLPageSource);
			data.setSource(new Text(connection.getInputStream()));
			data.setStatus(HTTPData.Status.OK);
			data.setException(null);
		} catch (Exception e) {
			data.setStatus(HTTPData.Status.FAILED);
			data.setException(e);
		}

		if (connection != null)
			connection.disconnect();
	}

	public HTTPData getHTTPData() {
		return data;
	}

	private static HTTPData performConnection(String address, Cookies cookies,
			PostData postData, Logger logger) {
		HTTPData data = new HTTPClient(address, cookies, postData, logger)
				.getHTTPData();

		if (!data.getStatus().isOk() && thrower) {
			Exception e = data.getException();
			if (e == null) {
				logger.error(unknownErrorWhenConnecting.useAsFormater(data
						.getAddress()));
			} else {
				logger.error(errorWhenConnecting.useAsFormater(data
						.getAddress(), e.getMessage()));
			}
		}

		return data;
	}

	public static HTTPData connect(String address, Cookies cookies,
			PostData postData, Logger logger) {
		HTTPData data = null;
		boolean done;
		do {
			logger.debug(startConnection.useAsFormater(address));
			data = performConnection(address, cookies, postData, logger);

			if (data.getResponseCode() == 302 && performRedirection) {
				address = data.getHeader().getHeaderField("Location");
				logger.debug(redirectConnection.useAsFormater(address));
				postData = null;
				done = false;
			} else {
				done = true;
			}
		} while (!done);

		return data;
	}

	public static HTTPData connect(String address, Cookies cookies,
			Logger logger) {
		return HTTPClient.connect(address, cookies, null, logger);
	}

	public static HTTPData connect(String address, Logger logger) {
		return HTTPClient.connect(address, null, null, logger);
	}

	public static boolean isThrower() {
		return thrower;
	}

	public static void setThrower(boolean thrower) {
		HTTPClient.thrower = thrower;
	}

	public static boolean isPerformRedirection() {
		return performRedirection;
	}

	public static void setPerformRedirection(boolean performRedirection) {
		HTTPClient.performRedirection = performRedirection;
	}

}
